/*
 * parser.cpp
 *
 *  Created on: 30/08/2013
 *      Author: pellarolojuani
 */

#include "parser.h"
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include "../Lexico/Termino.cpp"
#include <sys/types.h>
#include <dirent.h>


#define stopWords 20

Parser::Parser() {
	this->delimitadores = DELIMITADORES;
	pos = 0;
	numeroPalabra = 1;
	this->STOP_WORDS = new string[stopWords];
	this->STOP_WORDS[0] = "a";
	this->STOP_WORDS[1] = "an";
	this->STOP_WORDS[2] = "and";
	this->STOP_WORDS[3] = "at";
	this->STOP_WORDS[4] = "in";
	this->STOP_WORDS[5] = "on";
	this->STOP_WORDS[6] = "or";
	this->STOP_WORDS[7] = "the";
	this->STOP_WORDS[8] = "this";
	this->STOP_WORDS[9] = "that";
	this->STOP_WORDS[10] = "i";
	this->STOP_WORDS[11] = "to";
	this->STOP_WORDS[12] = "";	//MAGICO!!
	this->STOP_WORDS[13] = "who";
	this->STOP_WORDS[14] = "will";
	this->STOP_WORDS[15] = "with";
	this->STOP_WORDS[16] = "where";
	this->STOP_WORDS[17] = "when";
	this->STOP_WORDS[18] = "which";
	this->STOP_WORDS[19] = "you";

	this->cantDocumentos = 0;
	this->offsetnombreDocs = new long int;
	this->parserEOF = 0;

}

Parser::~Parser() {
	// TODO Auto-generated destructor stub
}

int Parser::getCantidadDocumentos(){
	return this->cantDocumentos;
}

int Parser::getNumeroPalabras(){
	return this->numeroPalabra;
}

bool Parser::esStopWord(string unTermino){
	for (int i=0; i<stopWords; i++){
		if (strcmp(unTermino.c_str(), this->STOP_WORDS[i].c_str())== 0) return true;
	}
	return false;
}

bool Parser::esMayor3caracteres(string unTermino){

	if (unTermino.length() > 3) return true;
	return false;
}


FILE* Parser::abrirArchivo(string unNombre){
	FILE* handle;
	handle = fopen(unNombre.c_str() ,"r");

	//caso en el que no se puede abrir el archivo
	if ( handle == 0 ){
	    cout<<"ERROR AL ABRIR EL ARCHIVO!!!"<<endl;
	  }

	return handle;
}

string Parser::aMinuscula(string unaPalabra){

	for (int i=0; i<strlen(unaPalabra.c_str()); i++){

		if (unaPalabra[i] >= 0x41 && unaPalabra[i] <= 0x5A)//intervalo de alfabeto mayuscula
			unaPalabra[i] = unaPalabra[i] + 0x20; // distancia entre una letra mayuscula y minuscula
												  // en ASCII
	}
	return unaPalabra;
}

string Parser::sacarFinDeLinea(string unaPalabra){

	if (unaPalabra[strlen(unaPalabra.c_str())-1] == '\n') // c_str transforma el strifng a un array
		unaPalabra = unaPalabra.substr(0,strlen(unaPalabra.c_str()));
		// substr copia el string desde la posicion 0 hasta la ante ultima posicion
		// asi descarta el fin de linea

	return unaPalabra;
}

bool Parser::esDelimitador(char c){
	//Determino si es una letra mediante codigo ascii.

			  //a			 z			   A		    Z
	if (((c >= 97) && (c <= 122)) ||((c >= 65) && (c <= 90)) ||( c == 195 ) ||
//			(c == 161) || (c == 129)|| (c == 169) ||				//Acentos
//			(c == 137) || (c == 173)|| (c == 141) || (c == 47) ||	//Acentos
			(c == 179) || (c == 147)|| (c == 186) || (c == 154) || (c == 177)|| (c == 145)){

			return false ;

		} else {
			if( (c > 47) && (c <= 57)){
				return false ;
			}

		}
		return true ;
}

int Parser::getUltimaPosicion(){

	return this->pos;

}

void Parser::resetUltimaPosicion(){

	this->pos=0;
	this->numeroPalabra=1;	//NO SE SI LO NECESITO!!!

}


string* Parser::parsearLinea(string str, int maxPosicionesLinea, int *canTerminos){
	//Funcion que parsea una linea de entrada devolviendo un vector de strings.
	//El vector en el que se almacenan los terminos se recibe como parametro
	//aca se van a ir almacenando todas las palabras de la linea


	//Proceso caracter a caracter y voy formando palabras.
	string palabra = "";
	unsigned int i = 0;
	int longitud = 0;
	unsigned int indiceComienzoPalabra = 0;
	unsigned int indicePalabra = 0;

	string* arrayPalabras = new string[maxPosicionesLinea];

	while ( i < str.length() ){
		char caracter = str.at(i);

		if ((this->esDelimitador(caracter)) && (i!=0)){
			string palabra;
			palabra = str.substr(indiceComienzoPalabra, (i-indiceComienzoPalabra));
			i++;

			indiceComienzoPalabra=i;
			//Se encontró una palabra.
			this->numeroPalabra++;	//NO SE SI LO NECESITO!!!

			arrayPalabras[indicePalabra] = this->aMinuscula(palabra);
			indicePalabra++;


			bool esCaracterFinal = false;
			if(i < str.length()){
				caracter=str.at(i);
			} else
				esCaracterFinal = true;

			//Si llego a tener varios delimitadores seguidos, por ejemplo "; " los escapeo.
			while((this->esDelimitador(caracter)&&!esCaracterFinal)){
				i++;
				indiceComienzoPalabra=i;
				if(i < str.length()){
					caracter=str.at(i);
				} else
					esCaracterFinal = true;
			}

		}//fin IF
		else if ((this->esDelimitador(caracter))&&(i == 0)){
			bool esCaracterFinal = false;
			while((this->esDelimitador(caracter)&&!esCaracterFinal)){
				i++;
				indiceComienzoPalabra=i;
				if(i < str.length()){
					caracter=str.at(i);
				} else
					esCaracterFinal = true;
			}
		}//fin ELSE
		else if (i == str.length()-1) {
			string palabra = str.substr(indiceComienzoPalabra);
			palabra = sacarFinDeLinea(palabra);
			arrayPalabras[indicePalabra] = aMinuscula(palabra);
			numeroPalabra++;

			indicePalabra++;
			i++;
		}//fin ELSE IF

		else
			i++;
		pos++;


	}//fin WHILE
	*canTerminos = indicePalabra;
	return arrayPalabras;

}//fin PARSEAR_LINEA

int Parser::contarDocumentosDeDirectorio(char *unDirectorio){

	DIR *dir;
	struct dirent *directorio;
	int cantDocs = 0;

	dir = opendir (unDirectorio);
	if (dir == NULL) cout<<"No se pudo abrir el directorio"<<endl;

	while ((directorio = readdir (dir)) != NULL ) {
		if(directorio->d_type & DT_REG){
			cantDocs ++;

		}
	}
	delete this->offsetnombreDocs;
	this->offsetnombreDocs = new long int[cantDocs];
	closedir (dir);
	return cantDocs;
}

void Parser::parsearArchivo(FILE* dirAct, int *terminosLinea,
							int *terminosDoc, abb::ArbolB<Termino, ORDEN_NODO> *lexico, int doc){
	/*dirAct es la direccion al comienzo del archivo que se quiere parsear.
	 * El archivo tiene que estar previamente abierto*/
	/*
	 * vamos llamando a la funcion parsearLinea hasta leer todo el texto y
	 * vamos almacenando todos los terminos en un vector.
	 *
	 * */

	//Paso a abrir el directorio y parsearlo linea por linea
	char linea[MAX_POSICIONES_LINEA];

	while (fgets(linea, MAX_POSICIONES_LINEA, dirAct) != NULL) {
		string* parseo = parsearLinea(linea, MAX_POSICIONES_LINEA, terminosLinea);

		for (int i = 0; i < *terminosLinea; i++){
			if (!this->esStopWord(parseo[i]) && this->esMayor3caracteres(parseo[i])){ //filtro todos los stopWords y no los almaceno

				//VEO SI YA ESTA EN EL ABB
				Termino unaPalabra = Termino(this->cantDocumentos);
				unaPalabra.setTermino(parseo[i]);
				unaPalabra.aumentarFrecuenciaDoc(doc);
				bool esta = lexico->buscar(unaPalabra);

				if (esta) { //SI YA ESTA ACTUALIZO FRECUENCIA
					unaPalabra = lexico->buscarYdevolver(unaPalabra);
					unaPalabra.aumentarFrecuenciaDoc(doc);

					lexico->modify(unaPalabra);

				}
				else {//SI NO ESTA LO INSERTO.
					lexico->insertar(unaPalabra);
					(*terminosDoc) ++;
				}
			} //end IF
		}//end FOR
	}//end WHILE

	fclose(dirAct);

	return;
}//end PARSEAR_ARCHIVO

/*void Parser::parsearArchivoIndependiente(FILE* dirAct, int *terminosLinea, int *terminosDoc,
						abb::ArbolB<Termino, ORDEN_NODO> *lexico){

	char linea[MAX_POSICIONES_LINEA];

	while (fgets(linea, MAX_POSICIONES_LINEA, dirAct) != NULL) {
		string* parseo = parsearLinea(linea, MAX_POSICIONES_LINEA, terminosLinea);

		for (int i = 0; i < *terminosLinea; i++){
			if (!this->esStopWord(parseo[i])){ //filtro todos los stopWords y no los almaceno

				//VEO SI YA ESTA EN EL ABB
				Termino unaPalabra = Termino(1);
				unaPalabra.setTermino(parseo[i]);
				unaPalabra.aumentarFrecuenciaDoc(1);//MODIFICARRR
				bool esta = lexico->buscar(unaPalabra);

				if (esta) { //SI YA ESTA ACTUALIZO FRECUENCIA	//MODIFICAR ESTA PARTE!!!
					unaPalabra = lexico->buscarYdevolver(unaPalabra);
					unaPalabra.aumentarFrecuenciaDoc(1);

					lexico->modify(unaPalabra);

				}

			} //end IF
		}//end FOR
	}//end WHILE

	fclose(dirAct);

	return;
}*/


void Parser::parsearDirectorio(char* directorioRuta, abb::ArbolB<Termino,ORDEN_NODO>* lexico){

	DIR *dir;
	struct dirent *directorio;
	FILE *unArchivo;
	this->cantDocumentos = this->contarDocumentosDeDirectorio(directorioRuta);
	int i = 0; // primera posicion donde se almacena el primer archivo
	int* terminosLinea = new int();
	int* terminosDoc = new int();
	*terminosLinea = 0;
	*terminosDoc = 0;


	FILE *archivoNombres = fopen("nombreArchivos.txt", "w");
	int contadorArchivos = 0;

	if ((dir = opendir(directorioRuta)) == NULL) {
		cout << "El directorio " << directorio->d_name << " no pudo a abrirse."<< endl;
	}
	/*conservamos el directorio para luego volver a ser leido*/
	FILE *archNombreDir = fopen("directorioParseado.txt", "w");
	fputs(directorioRuta, archNombreDir);
	fclose(archNombreDir);

	cout<<"Parseando directorio. Por favor espere..."<<endl;
	while ((directorio = readdir (dir)) != NULL ) {
		if(directorio->d_type & DT_REG){
			char* nombreDirectorio = directorio->d_name;
			offsetnombreDocs[contadorArchivos] = ftell(archivoNombres);
			fputs(nombreDirectorio, archivoNombres);
			fputc('\n', archivoNombres);

			char ruta[1024] = "";
			strcat(ruta, directorioRuta);
			strcat(ruta, "/");
			strcat(ruta, nombreDirectorio);	//a esta altura en ruta ya tenemos almacenado
											//la primera direccion a un documento de texto
											//para ser procesado.
			unArchivo = this->abrirArchivo(ruta);
			cout<<"     "<<contadorArchivos<<": "<<directorio->d_name<<endl;
			this->parsearArchivo(unArchivo, terminosLinea, terminosDoc, lexico, i);
			contadorArchivos ++;
			i++;


		} //end IF
	}//end WHILE

	fclose(archivoNombres);
	return;
}
